-- Expression Parser --

	-- Parse scanner input tokens according to operator tables given.
	-- Define parse.expressionNode to parse terminals (Numbers etc.)

	-- Operator list definition sample.  Each item consists of:
	--   [Name in output tree] [Token] [LEFT/RIGHT association]
	--
	-- Also a different line for parentheses definition, if you need them.

-- :- parser.new,
-- parser.operators (
--   ADDop (SYM "+") LEFT,
--   SUBop (SYM "-") RIGHT,
--   NEGop (SYM "-") PREFIX,
--   MULop (SYM "*") LEFT,
--   DIVop (SYM "/") RIGHT,
--   (SYM "(") (SYM ")") PAREN,
-- ) #


:- import "%%/lib/scanner.sl" #

:- structure.define (PARSER scanner operators:list nodeParser) #

parse.expression .parser .tree :-
	parser.operators .parser .chain,
	parse.chain .parser .chain .tree #

parse.chain .parser .chain .tree :- -- Left-associative operator
	.chain = (.op .token LEFT, .chain1) !
	parse.chain .parser .chain1 .left,
	parser.scanner .parser .sc,
	if (scan.match .sc .token) then (
		parse.chain .parser .chain .right,
		.tree = .op .left .right
	) else (
	  .tree = .left
	) ! #
parse.chain .parser .chain .tree :- -- Right-associative operator
	.chain = (. . RIGHT, .chain1) !
	parse.chain .parser .chain1 .left,
	parse.rightPhrase .parser .chain .left .tree ! #
parse.chain .parser .chain .tree :- -- Prefix operator
	.chain = (.op .token PREFIX, .chain1) !
	parser.scanner .parser .sc,
	if (scan.match .sc .token) then (
		parse.chain .parser .chain .tree0,
		.tree = .op .tree0
	) else (
		parse.chain .parser .chain1 .tree
	) #
parse.chain .parser .chain .tree :- -- Postfix operator
	.chain = (.op .token POSTFIX, .chain1) !
	parse.chain .parser .chain1 .tree0,
	parser.scanner .parser .sc,
	if (scan.match .sc .token) then (
		.tree = .op .tree0
	) else (
		.tree = .tree0
	) #
parse.chain .parser (.begin .end PAREN, .chain1) .tree :- -- Parentheses
	parser.scanner .parser .sc,
	if (scan.match .sc .begin) then (
		parse.expression .parser .tree,
		scan.match .sc .end
	) else (
		parse.chain .parser .chain1 .tree
	) #
parse.chain .parser $ .element :- -- Node element
	parser.nodeParser .parser .nodeParser,
	.nodeParser .parser .element #

parse.rightPhrase .parser .chain .left .tree :-
	.chain = ((.op .token RIGHT), .chain1),
	parser.scanner .parser .sc,
	scan.match .sc .token,
	parse.chain .parser .chain1 .right,
	parse.rightPhrase .parser .chain (.op .left .right) .tree #
parse.rightPhrase . . .tree .tree #
